package org.deng.vertx.web.verticle;

import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import com.alibaba.fastjson.JSON;

import org.deng.vertx.web.controller.BodyController;
import org.deng.vertx.web.controller.DemoController;
import org.deng.vertx.web.controller.HelloController;
import org.deng.vertx.web.controller.RouterController;
import org.deng.vertx.web.controller.SessionController;
import org.deng.vertx.web.controller.UserController;

import io.vertx.core.AbstractVerticle;
import io.vertx.core.Context;
import io.vertx.core.Vertx;
import io.vertx.core.http.HttpMethod;
import io.vertx.core.http.HttpServerRequest;
import io.vertx.core.http.HttpServerResponse;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.FileUpload;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.RoutingContext;
import io.vertx.ext.web.handler.BodyHandler;
import io.vertx.ext.web.handler.SessionHandler;
import io.vertx.ext.web.sstore.SessionStore;
import lombok.extern.slf4j.Slf4j;

/**
 * @author 邓力宾
 * @date 2021/8/25 15:07
 * @desc web服务器
 */
@Slf4j
public class WebVerticle extends AbstractVerticle {
    private final List<RouterController> controllers = new LinkedList<>();

    

    @Override
    public void init(Vertx vertx, Context context) {
        super.init(vertx, context);
        log.info("WebVerticle初始化...");
    }
    
    @Override
    public void start() throws Exception {
        SessionHandler sessionHandler = SessionHandler.create(SessionStore.create(vertx));
        log.info("{} start方法, 当前线程:{}", getClass().getName(), Thread.currentThread().getName());
        
        //路由
        Router router = Router.router(vertx);
        //配置sesion
        router.route().handler(sessionHandler);
        //用于处理request body
        BodyHandler bodyHandler = BodyHandler.create()
                                             .setBodyLimit(-1L) //设置body限制大小
                                             .setUploadsDirectory("./upload") //文件上传目录
                                             .setDeleteUploadedFilesOnEnd(false);//是否删除上传的文件
                                             
        router.route().handler(bodyHandler);
        //错误捕捉
        router.errorHandler(500, ctx ->{
            ctx.failure().printStackTrace();
            ctx.response().end("内部错误");
        });

        //注册controller
        reisterController(router);
        
        vertx.createHttpServer()
                //.requestHandler(this::helloWorld)
                //.requestHandler(this::responseJson)
                .requestHandler(router) //使用路由
                .listen(8888, http->{
            if(http.succeeded()) {
                log.info("启动成功，端口:{}", 8888);
            }else {
                log.error("web启动失败", http.cause());
            }
        });
    }

    /**
     * 配置路由
     * @param router 路由器
     */
    private void configRouter(Router router){
   
        for (RouterController controller : controllers) {
            controller.configRouter(router); //交给controller
        }
        router.route("/").handler(this::index);
        router.route("/getUserInfo/:id").handler(this::getUserInfo);
        router.route("/postForm").method(HttpMethod.POST).handler(this::getFormData);
        router.route("/postJson").method(HttpMethod.POST).handler(this::getJson);

    }

    /**
     * 注册controller
     * @param router
     */
    private void reisterController(Router router){
        //创建controller
        createControllers();
        //配置路由
        configRouter(router);
    }

    /**
     * 添加controller
     */
    private void createControllers(){
        this.controllers.add(new UserController(vertx));
        this.controllers.add(new HelloController(vertx));
        this.controllers.add(new DemoController(vertx));
        this.controllers.add(new SessionController(vertx));
        this.controllers.add(new BodyController(vertx));
    }
    /**
     * hello world
     */
    private void helloWorld(HttpServerRequest req){
        req.response()
                .putHeader("content-type", "text/plain")
                .end("Hello from Vert.x!");
    }

    /**
     * 返回json
     */
    private void responseJson(HttpServerRequest req){
        req.response()
                .putHeader("content-type", "application/json")
                .end(new JsonObject().put("hello", "world").toString());

    }



    /**
     * 主页
     * @param ctx 路由上下文
     */
    private void index(RoutingContext ctx){
        HttpServerResponse response = ctx.response();
        String name = ctx.request().getParam("name"); //获取第一个个
        response.putHeader("content-type", "text/plain;charset=utf-8");
        // Write to the response and end it
        List<String> names = ctx.queryParam("name"); //获取多个
        response.end("主页，names = "+ JSON.toJSONString(names)+", name = "+name);
    }

    /**
     * 获取用户信息
     * @param ctx 路由上下文
     */
    private void getUserInfo(RoutingContext ctx){
        // This handler will be called for every request
        HttpServerResponse response = ctx.response();
        response.putHeader("content-type", "application/json");
        String id = ctx.pathParam("id"); //获取路径参数
        // Write to the response and end it
        response.end(new JsonObject()
                .put("name", "李四")
                .put("age", 12)
                .put("id", id)
                .toString());
    }

    /**
     * 获取request body 表单数据
     * @param ctx 路由上下文
     */
    private void getFormData(RoutingContext ctx){
        String name = ctx.request().getFormAttribute("name");
        List<FileUpload> fileUploads = ctx.fileUploads();
        for (FileUpload fileUpload : fileUploads) {
            String fileName = fileUpload.fileName();
            log.info("上传文件,fileName="+fileName+ //文件名
                    ",uploadFileName="+fileUpload.uploadedFileName()+//保存后的文件名（默认保存到./file-uploads目录）
                    ",name="+fileUpload.name()); //表单中文件的参数名
        }
        ctx.json(new JsonObject().put("name", name));
    }
    /**
     * 获取request body json数据
     * @param ctx 路由上下文
     */
    private void getJson(RoutingContext ctx){
        JsonObject bodyAsJson = ctx.getBodyAsJson();
        ctx.json(bodyAsJson);
    }


}
